/**
 * 消息控制器
 * 处理消息相关的业务逻辑
 */
const asyncHandler = require('express-async-handler');
const mongoose = require('mongoose');
const Message = require('../models/message');
const Conversation = require('../models/conversation');
const User = require('../models/user');
const cloudinary = require('../config/cloudinary');

/**
 * 获取与指定用户的聊天记录
 */
exports.getMessages = async (req, res) => {
  try {
    const currentUserId = req.user.id;
    const receiverId = req.params.userId;
    
    // 验证参数
    if (!mongoose.Types.ObjectId.isValid(receiverId)) {
      return res.status(400).json({ message: '无效的用户ID' });
    }
    
    // 查询消息（当前用户发送或接收的）
    const messages = await Message.find({
      $or: [
        { sender: currentUserId, receiver: receiverId },
        { sender: receiverId, receiver: currentUserId }
      ]
    })
    .sort({ createdAt: 1 }) // 按时间升序
    .populate('sender', 'username avatar');
    
    // 更新未读消息为已读
    await Message.updateMany(
      { sender: receiverId, receiver: currentUserId, status: { $ne: 'read' } },
      { status: 'read', readAt: new Date() }
    );
    
    // 更新对话中的未读消息计数
    const conversation = await Conversation.findOne({
      participants: { $all: [currentUserId, receiverId] }
    });
    
    if (conversation) {
      const unreadCount = { ...conversation.unreadCount.toObject() };
      unreadCount[currentUserId] = 0;
      conversation.unreadCount = new Map(Object.entries(unreadCount));
      await conversation.save();
    }
    
    res.json(messages);
  } catch (error) {
    console.error('获取消息错误:', error);
    res.status(500).json({ message: '服务器错误' });
  }
};

/**
 * 发送消息
 * @route POST /api/messages
 * @access Private
 */
const sendMessage = asyncHandler(async (req, res) => {
  const { conversationId, content, type = 'text' } = req.body;

  // 验证输入
  if (!conversationId || !content) {
    res.status(400);
    throw new Error('请提供对话ID和消息内容');
  }

  // 获取对话
  const conversation = await Conversation.findById(conversationId);
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 验证用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('您不是此对话的参与者');
  }

  // 创建消息
  const message = await Message.create({
    conversation: conversationId,
    sender: req.user._id,
    content,
    type,
    readBy: [req.user._id] // 发送者默认已读
  });

  // 填充发送者信息并返回
  await message.populate('sender', 'username avatar');

  // 更新对话的最新消息和时间
  conversation.latestMessage = message._id;
  await conversation.save();

  res.status(201).json(message);
});

/**
 * 获取消息详情
 * @route GET /api/messages/:messageId
 * @access Private
 */
const getMessageById = asyncHandler(async (req, res) => {
  const message = await Message.findById(req.params.messageId)
    .populate('sender', 'username avatar')
    .populate('readBy', 'username avatar');

  // 检查消息是否存在
  if (!message) {
    res.status(404);
    throw new Error('消息未找到');
  }

  // 获取对话
  const conversation = await Conversation.findById(message.conversation);
  
  // 验证用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('您无权查看此消息');
  }

  // 如果用户未读此消息，则标记为已读
  if (!message.readBy.includes(req.user._id)) {
    message.readBy.push(req.user._id);
    await message.save();
  }

  res.json(message);
});

/**
 * 删除消息
 * @route DELETE /api/messages/:messageId
 * @access Private
 */
const deleteMessage = asyncHandler(async (req, res) => {
  const message = await Message.findById(req.params.messageId);

  // 检查消息是否存在
  if (!message) {
    res.status(404);
    throw new Error('消息未找到');
  }

  // 验证用户是否为消息发送者
  if (message.sender.toString() !== req.user._id.toString()) {
    res.status(403);
    throw new Error('只有消息发送者可以删除消息');
  }

  // 如果是文件类型的消息，删除云存储中的文件
  if (message.type === 'image' || message.type === 'file') {
    try {
      // 从URL提取公共ID
      const publicId = message.content.split('/').pop().split('.')[0];
      await cloudinary.uploader.destroy(publicId);
    } catch (error) {
      console.error('删除云存储文件失败:', error);
      // 继续删除消息，即使文件删除失败
    }
  }

  // 删除消息
  await message.remove();

  // 检查是否是对话的最新消息，如果是则更新对话的最新消息
  const conversation = await Conversation.findById(message.conversation);
  if (conversation.latestMessage.toString() === req.params.messageId) {
    // 查找对话中的最新消息
    const latestMessage = await Message.findOne({ conversation: message.conversation })
      .sort({ createdAt: -1 });
    
    conversation.latestMessage = latestMessage ? latestMessage._id : null;
    await conversation.save();
  }

  res.json({ message: '消息已删除' });
});

/**
 * 上传文件消息
 * @route POST /api/messages/upload
 * @access Private
 */
const uploadFile = asyncHandler(async (req, res) => {
  const { conversationId } = req.body;

  // 验证输入
  if (!conversationId || !req.file) {
    res.status(400);
    throw new Error('请提供对话ID和文件');
  }

  // 获取对话
  const conversation = await Conversation.findById(conversationId);
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 验证用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('您不是此对话的参与者');
  }

  // 上传文件到Cloudinary
  try {
    const result = await cloudinary.uploader.upload(req.file.path, {
      folder: 'chat_app/messages',
      resource_type: 'auto'
    });

    // 判断文件类型
    let fileType = 'file';
    if (req.file.mimetype.startsWith('image/')) {
      fileType = 'image';
    } else if (req.file.mimetype.startsWith('video/')) {
      fileType = 'video';
    } else if (req.file.mimetype.startsWith('audio/')) {
      fileType = 'audio';
    }

    // 创建消息
    const message = await Message.create({
      conversation: conversationId,
      sender: req.user._id,
      content: result.secure_url,
      type: fileType,
      readBy: [req.user._id],
      fileInfo: {
        filename: req.file.originalname,
        size: req.file.size,
        mimetype: req.file.mimetype,
        url: result.secure_url
      }
    });

    // 填充发送者信息并返回
    await message.populate('sender', 'username avatar');

    // 更新对话的最新消息和时间
    conversation.latestMessage = message._id;
    await conversation.save();

    res.status(201).json(message);
  } catch (error) {
    res.status(500);
    throw new Error('文件上传失败: ' + error.message);
  }
});

/**
 * 获取所有对话
 */
exports.getConversations = async (req, res) => {
  try {
    const currentUserId = req.user.id;
    
    // 查询当前用户参与的所有对话
    const conversations = await Conversation.find({
      participants: currentUserId
    })
    .populate('participants', 'username avatar isOnline lastSeen')
    .populate('lastMessage')
    .sort({ updatedAt: -1 }); // 按最后更新时间降序
    
    // 处理结果以便前端显示
    const result = conversations.map(conv => {
      // 找到对话中的另一个用户
      const otherParticipant = conv.participants.find(
        p => p._id.toString() !== currentUserId
      );
      
      // 获取当前用户的未读消息数
      const unreadCount = conv.unreadCount.get(currentUserId) || 0;
      
      return {
        id: conv._id,
        contact: otherParticipant,
        lastMessage: conv.lastMessage,
        unreadCount,
        updatedAt: conv.updatedAt
      };
    });
    
    res.json(result);
  } catch (error) {
    console.error('获取对话列表错误:', error);
    res.status(500).json({ message: '服务器错误' });
  }
};

/**
 * 标记对话中的所有消息为已读
 */
exports.markConversationAsRead = async (req, res) => {
  try {
    const currentUserId = req.user.id;
    const { conversationId } = req.params;
    
    // 验证参数
    if (!mongoose.Types.ObjectId.isValid(conversationId)) {
      return res.status(400).json({ message: '无效的对话ID' });
    }
    
    // 查找对话
    const conversation = await Conversation.findById(conversationId);
    
    if (!conversation) {
      return res.status(404).json({ message: '对话不存在' });
    }
    
    // 确认当前用户是对话参与者
    if (!conversation.participants.includes(currentUserId)) {
      return res.status(403).json({ message: '没有权限访问此对话' });
    }
    
    // 找到对话中的另一个参与者
    const otherParticipantId = conversation.participants.find(
      id => id.toString() !== currentUserId
    );
    
    // 更新未读消息为已读
    await Message.updateMany(
      { sender: otherParticipantId, receiver: currentUserId, status: { $ne: 'read' } },
      { status: 'read', readAt: new Date() }
    );
    
    // 更新对话中的未读消息计数
    const unreadCount = { ...conversation.unreadCount.toObject() };
    unreadCount[currentUserId] = 0;
    conversation.unreadCount = new Map(Object.entries(unreadCount));
    await conversation.save();
    
    res.json({ message: '对话已标记为已读' });
  } catch (error) {
    console.error('标记对话为已读错误:', error);
    res.status(500).json({ message: '服务器错误' });
  }
};

module.exports = {
  sendMessage,
  getMessageById,
  deleteMessage,
  uploadFile
}; 